using System.Net.Sockets;
using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Shared.Constants;
using SumerCoreDevOps.Shared.Enums;
using SumerCoreDevOps.Shared.Models;

namespace SumerCoreDevOps.Infrastructure.Tcp;

/// <summary>
/// TCP 客户端（执行节点端）
/// </summary>
public class TcpClient : IDisposable
{
    private readonly ILogger<TcpClient> _logger;
    private readonly TcpMessageCodec _codec;
    private string _serverHost;
    private int _serverPort;
    private System.Net.Sockets.TcpClient? _client;
    private NetworkStream? _stream;
    private CancellationTokenSource? _cts;
    private bool _isConnected;
    private int _reconnectAttempts;

    public event Func<TcpMessageType, object, Task>? OnMessageReceived;
    public event Func<Task>? OnConnected;
    public event Func<Task>? OnDisconnected;

    public bool IsConnected => _isConnected && _client?.Connected == true;

    public TcpClient(ILogger<TcpClient> logger, byte[] aesKey, string serverHost, int serverPort)
    {
        _logger = logger;
        _codec = new TcpMessageCodec(aesKey);
        _serverHost = serverHost;
        _serverPort = serverPort;
    }

    /// <summary>
    /// 更新服务器地址和端口（用于重新连接到新的服务器）
    /// </summary>
    public void UpdateServerAddress(string serverHost, int serverPort)
    {
        _logger.LogInformation("更新服务器地址: {OldHost}:{OldPort} -> {NewHost}:{NewPort}",
            _serverHost, _serverPort, serverHost, serverPort);
        _serverHost = serverHost;
        _serverPort = serverPort;
    }

    /// <summary>
    /// 重新连接到服务器（使用新的地址和端口）
    /// </summary>
    public async Task ReconnectToNewServerAsync()
    {
        _logger.LogInformation("开始重新连接到新服务器: {Host}:{Port}", _serverHost, _serverPort);

        // 断开当前连接
        await DisconnectAsync();

        // 等待一小段时间，确保完全断开
        await Task.Delay(1000);

        // 重新连接
        await ConnectAsync();
    }

    /// <summary>
    /// 连接到服务器
    /// </summary>
    public async Task ConnectAsync(CancellationToken cancellationToken = default)
    {
        if (_isConnected)
        {
            return;
        }

        _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
        await ConnectWithRetryAsync(_cts.Token);

        // 启动接收消息循环
        _ = Task.Run(async () => await ReceiveMessagesAsync(_cts.Token), _cts.Token);

        // 启动心跳循环
        _ = Task.Run(async () => await HeartbeatLoopAsync(_cts.Token), _cts.Token);
    }

    /// <summary>
    /// 断开连接
    /// </summary>
    public async Task DisconnectAsync()
    {
        if (!_isConnected)
        {
            return;
        }

        _isConnected = false;
        _cts?.Cancel();
        _stream?.Close();
        _client?.Close();

        _logger.LogInformation("Disconnected from server");

        if (OnDisconnected != null)
        {
            await OnDisconnected();
        }
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    public async Task SendMessageAsync<T>(TcpMessageType messageType, T body, bool compress = false)
        where T : class
    {
        if (!IsConnected)
        {
            throw new InvalidOperationException("Not connected to server");
        }

        try
        {
            byte[] data = _codec.Encode(messageType, body, compress);
            await _stream!.WriteAsync(data);
            await _stream.FlushAsync();

            _logger.LogDebug("Sent message {MessageType}, size: {Size} bytes", messageType, data.Length);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send message {MessageType}", messageType);
            _isConnected = false;
            await ReconnectAsync();
            throw;
        }
    }

    /// <summary>
    /// 带重试的连接
    /// </summary>
    private async Task ConnectWithRetryAsync(CancellationToken cancellationToken)
    {
        _reconnectAttempts = 0;

        while (_reconnectAttempts < TcpProtocolConstants.MaxReconnectAttempts && !cancellationToken.IsCancellationRequested)
        {
            try
            {
                _client = new System.Net.Sockets.TcpClient();
                await _client.ConnectAsync(_serverHost, _serverPort, cancellationToken);
                _stream = _client.GetStream();
                _isConnected = true;
                _reconnectAttempts = 0;

                _logger.LogInformation("Connected to server {Host}:{Port}", _serverHost, _serverPort);

                if (OnConnected != null)
                {
                    await OnConnected();
                }

                return;
            }
            catch (Exception ex)
            {
                _reconnectAttempts++;
                _logger.LogWarning(ex, "Failed to connect to server (attempt {Attempt}/{Max})",
                    _reconnectAttempts, TcpProtocolConstants.MaxReconnectAttempts);

                if (_reconnectAttempts < TcpProtocolConstants.MaxReconnectAttempts)
                {
                    await Task.Delay(
                        TimeSpan.FromSeconds(TcpProtocolConstants.ReconnectIntervalSeconds),
                        cancellationToken);
                }
            }
        }

        throw new InvalidOperationException($"Failed to connect to server after {TcpProtocolConstants.MaxReconnectAttempts} attempts");
    }

    /// <summary>
    /// 重连
    /// </summary>
    private async Task ReconnectAsync()
    {
        _logger.LogInformation("Attempting to reconnect...");

        try
        {
            _stream?.Close();
            _client?.Close();
            await ConnectWithRetryAsync(_cts?.Token ?? CancellationToken.None);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to reconnect");
        }
    }

    /// <summary>
    /// 接收消息循环
    /// </summary>
    private async Task ReceiveMessagesAsync(CancellationToken cancellationToken)
    {
        byte[] headerBuffer = new byte[TcpProtocolConstants.MessageHeaderLength];

        while (!cancellationToken.IsCancellationRequested)
        {
            try
            {
                if (!IsConnected)
                {
                    await Task.Delay(1000, cancellationToken);
                    continue;
                }

                // 读取消息头
                int headerBytesRead = 0;
                while (headerBytesRead < TcpProtocolConstants.MessageHeaderLength)
                {
                    int read = await _stream!.ReadAsync(
                        headerBuffer.AsMemory(headerBytesRead,
                        TcpProtocolConstants.MessageHeaderLength - headerBytesRead),
                        cancellationToken);

                    if (read == 0)
                    {
                        _logger.LogWarning("Server closed connection");
                        _isConnected = false;
                        await ReconnectAsync();
                        break;
                    }

                    headerBytesRead += read;
                }

                if (!IsConnected) continue;

                // 解析消息头获取数据长度
                int dataLength = BitConverter.ToInt32(headerBuffer, 5);
                if (dataLength > TcpProtocolConstants.MaxMessageLength)
                {
                    _logger.LogWarning("Message too large: {Size} bytes", dataLength);
                    continue;
                }

                // 读取完整消息
                int totalLength = TcpProtocolConstants.MessageHeaderLength + dataLength + TcpProtocolConstants.CRC32Length;
                byte[] messageBuffer = new byte[totalLength];
                Array.Copy(headerBuffer, messageBuffer, TcpProtocolConstants.MessageHeaderLength);

                int bodyBytesRead = 0;
                int remainingBytes = dataLength + TcpProtocolConstants.CRC32Length;

                while (bodyBytesRead < remainingBytes)
                {
                    int read = await _stream!.ReadAsync(
                        messageBuffer.AsMemory(
                            TcpProtocolConstants.MessageHeaderLength + bodyBytesRead,
                            remainingBytes - bodyBytesRead),
                        cancellationToken);

                    if (read == 0)
                    {
                        _logger.LogWarning("Server closed connection");
                        _isConnected = false;
                        await ReconnectAsync();
                        break;
                    }

                    bodyBytesRead += read;
                }

                if (!IsConnected) continue;

                // 处理消息
                await ProcessMessageAsync(messageBuffer);
            }
            catch (OperationCanceledException)
            {
                break;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error in receive loop");
                _isConnected = false;
                await ReconnectAsync();
            }
        }
    }

    /// <summary>
    /// 处理接收到的消息
    /// </summary>
    private async Task ProcessMessageAsync(byte[] messageData)
    {
        try
        {
            // 获取消息类型
            TcpMessageType messageType = (TcpMessageType)messageData[3];

            _logger.LogDebug("Received message {MessageType}", messageType);

            // 根据消息类型解码
            object? body = messageType switch
            {
                TcpMessageType.RegisterResponse => _codec.Decode<Shared.Models.Messages.RegisterResponseMessage>(messageData)?.Body,
                TcpMessageType.AuthResponse => _codec.Decode<Shared.Models.Messages.AuthResponseMessage>(messageData)?.Body,
                TcpMessageType.HeartbeatResponse => _codec.Decode<Shared.Models.Messages.HeartbeatResponseMessage>(messageData)?.Body,
                TcpMessageType.WorkflowStepDispatch => _codec.Decode<Shared.Models.Messages.WorkflowStepDispatchMessage>(messageData)?.Body,
                TcpMessageType.CredentialResponse => _codec.Decode<Shared.Models.Messages.CredentialResponseMessage>(messageData)?.Body,
                TcpMessageType.CleanupCommand => _codec.Decode<Shared.Models.Messages.CleanupCommandMessage>(messageData)?.Body,
                TcpMessageType.ConfigurationChanged => _codec.Decode<Shared.Models.Messages.ConfigurationChangedMessage>(messageData)?.Body,
                _ => null
            };

            if (body != null && OnMessageReceived != null)
            {
                await OnMessageReceived(messageType, body);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing message");
        }
    }

    /// <summary>
    /// 心跳循环
    /// </summary>
    private async Task HeartbeatLoopAsync(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            try
            {
                await Task.Delay(
                    TimeSpan.FromSeconds(TcpProtocolConstants.HeartbeatIntervalSeconds),
                    cancellationToken);

                if (IsConnected)
                {
                    // 心跳消息会在外部触发，这里只是确保定时检查连接状态
                    _logger.LogDebug("Heartbeat check - connected: {IsConnected}", IsConnected);
                }
            }
            catch (OperationCanceledException)
            {
                break;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error in heartbeat loop");
            }
        }
    }

    public void Dispose()
    {
        DisconnectAsync().Wait();
        _cts?.Dispose();
        _stream?.Dispose();
        _client?.Dispose();
    }
}
